/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Description: Hmfs-tools zoned
 */

#ifndef HMFS_ZONED_H
#define HMFS_ZONED_H

#include <memory>
#include "device_manager.h"

#if defined(HAVE_LINUX_BLKZONED_H)
#include <linux/blkzoned.h>
#elif defined(HAVE_KERNEL_UAPI_LINUX_BLKZONED_H)
#include <kernel/uapi/linux/blkzoned.h>
#endif

namespace OHOS {
namespace Hmfs {
typedef int (ReportZonesCb)(int i, void *, void *);

#ifdef HAVE_LINUX_BLKZONED_H
struct BlockZone {
    uint64_t start;
    uint64_t len;
    uint64_t wp;
    uint8_t  type;
    uint8_t  cond;
    uint8_t  nonSeq;
    uint8_t  reset;
    uint8_t  resv[ZONED_RESV_SIZE];
    uint64_t capacity;
    uint8_t  reserved[ZONED_RESERVED_SIZE];
};

struct BlockZoneReport {
    uint64_t sector;
    uint32_t zoneCount;
    uint32_t flags;
    BlockZone zones[0];
};

static inline uint8_t GetBlockZoneType(BlockZone *zone)
{
    return zone->type;
}

static inline uint8_t GetBlockZoneCond(BlockZone *zone)
{
    return zone->cond;
}

static inline bool GetBlockZoneConv(BlockZone *zone)
{
    return (zone->type == BLK_ZONE_TYPE_CONVENTIONAL);
}

static inline bool GetBlockZoneSeqReq(BlockZone *zone)
{
    return (zone->type == BLK_ZONE_TYPE_SEQWRITE_REQ);
}

static inline bool GetBlockZoneSeqPref(BlockZone *zone)
{
    return (zone->type == BLK_ZONE_TYPE_SEQWRITE_PREF);
}

static inline bool GetBlockZoneSeq(BlockZone *zone)
{
    return (GetBlockZoneSeqReq(zone) || GetBlockZoneSeqPref(zone));
}

static inline bool GetBlockZoneEmpty(BlockZone *zone)
{
    return (GetBlockZoneCond(zone) == BLK_ZONE_COND_EMPTY);
}

static inline uint64_t GetBlockZoneSector(BlockZone *zone)
{
    return zone->start;
}

static inline uint64_t GetBlockZoneLength(BlockZone *zone)
{
    return zone->len;
}

static inline uint64_t GetBlockZoneWpSector(BlockZone *zone)
{
    return zone->wp;
}

static inline int GetBlockZoneNeedReset(BlockZone *zone)
{
    return static_cast<int>((zone)->reset);
}

static inline int GetBlockZoneNonSeq(BlockZone *zone)
{
    return static_cast<int>((zone)->nonSeq);
}

#define BLK_ZONE_REP_CAPACITY (1 << 0)

inline uint64_t GetBlockZoneSize(BlockZone *zone, uint32_t flags)
{
    return (flags & BLK_ZONE_REP_CAPACITY) ? zone->capacity : zone->len;
}

struct OneZoneReport {
    BlockZoneReport rep;
    BlockZone zone;
};
#endif
struct BlockZone;

class HmfsZoned {
public:
    static HmfsZoned &GetInstance();
#ifdef HAVE_LINUX_BLKZONED_H
    int GetSysFsPath(std::string &devPath, const std::string &attr, std::string &filePath);
    uint32_t HmfsGetZoneChunkSectors(DeviceInfo *deviceInfo);
#endif
    int HmfsResetZonesPart(DeviceInfo *deviceInfo, BlockZoneReport *zoneReport, uint64_t &sector,
        uint64_t sectorCount);
    int HmfsResetZones(DeviceInfo *deviceInfo);
    int HmfsGetZonedModel(DeviceInfo *deviceInfo);
    int HmfsGetZoneBlocks(DeviceInfo *deviceInfo);
    int HmfsCheckZones(DeviceInfo *deviceInfo);
    uint32_t HmfsGetUsableSegments(SuperBlockData *superBlock);
    int HmfsReportZone(int32_t fd, uint64_t sector, BlockZone *blkZone);

private:
    HmfsZoned() = default;
#ifdef HAVE_LINUX_BLKZONED_H
    void HmfsCheckZonesPart2(DeviceInfo *deviceInfo, BlockZoneReport *report,
        BlockZone *blockZone, uint32_t num, int &lastIsConv);
    int HmfsCheckZonesPart(DeviceInfo *deviceInfo, BlockZoneReport *report,
        uint64_t &sector, uint64_t &totalSectors, uint32_t &num);
    const char *GetBlkZoneTypeStr(BlockZone *blockZone);
    const char *GetBlkZoneCondStr(BlockZone *blockZone);
#endif
};
} // namespace Hmfs
} // namespace OHOS
#endif // HMFS_ZONED_H